using UnityEngine;
using System.Collections;

public class CameraController : MonoBehaviour
{
    // 单例模式
    public static CameraController ins;

    // 更新模式枚举
    [System.Serializable]
    public enum UpdateMode
    {
        Update,
        FixedUpdate,
        LateUpdate
    }

    // 目标变换
    public Transform target;

    // 旋转空间变换
    public Transform rotationSpace;

    // 更新模式
    public UpdateMode updateMode = UpdateMode.LateUpdate;

    // 是否锁定光标
    public bool lockCursor = true;

    // 平滑跟随
    public bool smoothFollow;

    // 平滑跟随速度
    public float followSpeed = 10f;

    // 当前距离目标的距离
    public float distance = 4f;

    // 最小距离
    public float minDistance = 2;

    // 最大距离
    public float maxDistance = 6;

    // 缩放速度
    public float zoomSpeed = 10f;

    // 缩放灵敏度
    public float zoomSensitivity = 1f;

    // 旋转灵敏度
    public float rotationSensitivity = 3.5f;

    // 垂直角度最小限制
    public float yMinLimit = 0;

    // 垂直角度最大限制
    public float yMaxLimit = 80;

    // 相对于相机旋转的目标偏移量
    public Vector3 offset = new Vector3(0.5f, 0, 0.3f);

    // 是否始终旋转到鼠标位置
    public bool rotateAlways = false;

    // 左键按下时旋转到鼠标位置
    public bool rotateOnLeftButton;

    // 右键按下时旋转到鼠标位置
    public bool rotateOnRightButton = true;

    // 中键按下时旋转到鼠标位置
    public bool rotateOnMiddleButton;

    // 当前 x 旋转角
    public float x { get; private set; }

    // 当前 y 旋转角
    public float y { get; private set; }

    // 目标距离
    public float distanceTarget { get; private set; }

    // 私有变量
    private Vector3 targetDistance, position;
    private Quaternion rotation = Quaternion.identity;
    private Vector3 smoothPosition;
    private Camera cam;

    // 初始化，设置参数为当前相机相对于目标的变换
    protected virtual void Awake()
    {
        ins = this;
        target = GameObject.FindWithTag("Player").transform;
        Vector3 angles = transform.eulerAngles;
        x = angles.y;
        y = angles.x;

        distanceTarget = distance;
        smoothPosition = transform.position;
        cam = GetComponent<Camera>();
        lastUp = rotationSpace != null ? rotationSpace.up : Vector3.up;

    }

    // 根据更新模式调用 UpdateTransform 方法
    protected virtual void Update()
    {
        if (updateMode == UpdateMode.Update) UpdateTransform();
    }

    protected virtual void FixedUpdate()
    {
        if (updateMode == UpdateMode.FixedUpdate) UpdateTransform();
    }

    protected virtual void LateUpdate()
    {
        UpdateInput();

        if (updateMode == UpdateMode.LateUpdate) UpdateTransform();
    }

    // 读取用户输入
    public void UpdateInput()
    {
        if (target == null || !cam.enabled) return;

        // 游标控制
        Cursor.lockState = lockCursor ? CursorLockMode.Locked : CursorLockMode.None;
        Cursor.visible = lockCursor ? false : true;

        // 是否应该旋转相机？
        // 只有当右键按下时才进行旋转
        bool rotate = (rotateOnRightButton && Input.GetMouseButton(1));

        // 旋转增量
        if (rotate)
        {
            x += Input.GetAxis("Mouse X") * rotationSensitivity;
            y = ClampAngle(y - Input.GetAxis("Mouse Y") * rotationSensitivity, yMinLimit, yMaxLimit);
        }

        // 距离变化
        distanceTarget = Mathf.Clamp(distanceTarget + zoomAdd, minDistance, maxDistance);
    }

    // 更新相机变换
    public void UpdateTransform()
    {
        UpdateTransform(Time.deltaTime);
    }

    private Quaternion r = Quaternion.identity;
    private Vector3 lastUp;

    public void UpdateTransform(float deltaTime)
    {
        if (target == null || !cam.enabled) return;

        // 距离变化
        distance += (distanceTarget - distance) * zoomSpeed * deltaTime;

        // 旋转
        rotation = Quaternion.AngleAxis(x, Vector3.up) * Quaternion.AngleAxis(y, Vector3.right);

        if (rotationSpace != null)
        {
            r = Quaternion.FromToRotation(lastUp, rotationSpace.up) * r;
            rotation = r * rotation;

            lastUp = rotationSpace.up;
        }

        // 平滑跟随
        if (!smoothFollow) smoothPosition = target.position;
        else smoothPosition = Vector3.Lerp(smoothPosition, target.position, deltaTime * followSpeed);

        // 位置计算
        position = smoothPosition + rotation * (offset - Vector3.forward * distance);

        // 更新相机位置和旋转
        transform.position = position;
        transform.rotation = rotation;
    }

    // 缩放输入
    private float zoomAdd
    {
        get
        {
            float scrollAxis = Input.GetAxis("Mouse ScrollWheel");
            if (scrollAxis > 0) return -zoomSensitivity;
            if (scrollAxis < 0) return zoomSensitivity;
            return 0;
        }
    }

    // 限制欧拉角
    private float ClampAngle(float angle, float min, float max)
    {
        if (angle < -360) angle += 360;
        if (angle > 360) angle -= 360;
        return Mathf.Clamp(angle, min, max);
    }
}